package top.lidee.common.service.twice.third.wechat.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.HttpPost;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import top.lidee.common.bean.WxPayV3Bean;
import top.lidee.common.dto.AccountInfo;
import top.lidee.common.service.StoreService;
import top.lidee.common.service.twice.management.*;
import top.lidee.common.service.twice.third.wechat.WechatPayJJCommonService;
import top.lidee.common.service.twice.third.wechat.WechatPayTyshService;
import top.lidee.common.to.wx.ty.*;
import top.lidee.framework.enums.CommonExceptionEnum;
import top.lidee.framework.result.GlobalCheck;
import top.lidee.framework.result.ResponseResult;
import top.lidee.repository.model.MtStore;
import top.lidee.repository.model.twice.pojo.applet.MtStoreCateEntity;
import top.lidee.repository.model.twice.pojo.management.MtProvincesNumTableEntity;
import top.lidee.repository.model.twice.pojo.management.MtStoreWechatInputPieceLogEntity;
import top.lidee.repository.model.twice.pojo.management.MtUploadCateCertificationLogEntity;
import top.lidee.repository.model.twice.pojo.management.TpbWechatBankAccountEntity;
import top.lidee.repository.model.twice.vo.management.WxTySuperAdminVo;
import top.lidee.utils.CopyBean;
import top.lidee.utils.MyCollUtil;

import java.security.cert.X509Certificate;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static top.lidee.framework.constant.RedisConstant.TY_LOCK_KEY;
import static top.lidee.framework.constant.WechatConstant.*;

/**
 * @author 张一恒
 * @version 1.0
 * @description:
 * @date 2024/10/18 14:41
 */
@Service("wechatPayTyshService")
@Slf4j
public class WechatPayTyshServiceImpl implements WechatPayTyshService {

    //微信V3支付Bean
    @Autowired
    private WxPayV3Bean wxPayV3Bean;

    //店铺业务接口
    @Autowired
    private StoreService storeService;

    @Autowired
    private WechatPayJJCommonService wechatPayJJCommonService;

    @Autowired
    private MtProvincesNumTableService mtProvincesNumTableService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Value("${applet.wx.miniapp.configs[0].appid}")
    private String appid;

    private static final String LOCK_VALUE = "tyshjj";


    /**
     * @param storeId
     * @param accountInfo
     * @return top.lidee.framework.result.ResponseResult
     * @description 特约商户进件（提交申请单）
     * 接口说明
     * 适用对象：服务商
     * 请求URL：https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/
     * 请求方式：POST
     * 频率限制：15/s
     * @author zhangyiheng
     * @date 2024/10/19 09:17
     */
    @Override
    public ResponseResult wxIncomingPartsTy(Integer storeId, AccountInfo accountInfo) {
        GlobalCheck.checkManagerAdmin(accountInfo.getManagerId());
        //频率限制：15/s，无法并发请求，并发的情况下每15-30秒内只能存在1个线程执行（所有线程加同一把锁，抢到锁的线程执行）。
        //过期时间30秒，如果业务在没问题的情况下超过了30秒说明代码本身有问题需要重写
        Boolean res = stringRedisTemplate.opsForValue().setIfAbsent(TY_LOCK_KEY, LOCK_VALUE, 30, TimeUnit.MILLISECONDS);
        long startTime = System.currentTimeMillis();
        if (Boolean.TRUE.equals(res)) {
            try {
                //上锁成功
                //获取店铺证照信息
                MtStore store = storeService.getById(storeId);

                TpbWechatBankAccountEntity tpbWechatBankAccount = null;
                MtStoreCateEntity cate = null;
                List<MtUploadCateCertificationLogEntity> mtUploadCateCertificationLogs = null;
                MtStoreWechatInputPieceLogEntity pieceLog = null;
                Map<String, Object> map = wechatPayJJCommonService.checkInfo(accountInfo.getManagerId(), store);

                if (CollUtil.isNotEmpty(map)) {
                    if (Objects.nonNull(map.get("tpbWechatBankAccount"))) {
                        tpbWechatBankAccount = (TpbWechatBankAccountEntity) map.get("tpbWechatBankAccount");
                    }

                    if (Objects.nonNull(map.get("cate"))) {
                        cate = (MtStoreCateEntity) map.get("cate");
                    }

                    if (Objects.nonNull(map.get("mtUploadCateCertificationLogs"))) {
                        mtUploadCateCertificationLogs = (List<MtUploadCateCertificationLogEntity>) map.get("mtUploadCateCertificationLogs");
                    }

                    if (Objects.nonNull(map.get("pieceLog"))) {
                        pieceLog = (MtStoreWechatInputPieceLogEntity) map.get("pieceLog");
                    }
                }


                WxTySuperAdminVo wxTySuperAdminVo = CopyBean.copyBean(pieceLog, WxTySuperAdminVo.class);


                //请求URL
                HttpPost httpPost = new HttpPost(wxPayV3Bean.getWxIncomingPartsTyUrl());

                WechatpayTyjjTo to = new WechatpayTyjjTo();


                String licenseStartTime = DateUtil.format(store.getLicenseStartTime(), "yyyy-MM-dd");
                String licenseEndTime = DateUtil.format(store.getLicenseEndTime(), "yyyy-MM-dd");

                String cardStartTime = DateUtil.format(store.getCardStartTime(), "yyyy-MM-dd");
                String cardEndTime = DateUtil.format(store.getCardEndTime(), "yyyy-MM-dd");
                //获取证书
                X509Certificate certificate = wechatPayJJCommonService.getCertificate(wxPayV3Bean.getWechatpayPath());


                to.setBusiness_code(store.getExternalId());

                //region Description 超级管理员信息
                superAdministratorInformation(certificate, to, wxTySuperAdminVo);
                //endregion

                //region Description 主体资料
                principalData(store, cate, licenseStartTime, licenseEndTime, mtUploadCateCertificationLogs, cardStartTime, cardEndTime, to,certificate);
                //endregion

                //region Description 经营资料
                businessInformation(store, to);
                //endregion

                //region Description 结算规则
                settlementRules(store, cate, mtUploadCateCertificationLogs, to);
                //endregion

                //region Description 结算银行账户
                clearingBankAccount(store, tpbWechatBankAccount, certificate, to);
                //endregion

                //region TODO Description 补充材料 非必填
                //根据实际审核情况，会额外要求商家提供指定的补充资料，可能初提交不用填写，如果出现问题微信会指定需要哪些补充材料
                Addition_info additionInfo = new Addition_info();
                to.setAddition_info(additionInfo);
                //endregion

                //构建body
                wechatPayJJCommonService.doWXRES(storeId, to, httpPost, store, "特约商户进件", pieceLog);

                //请求微信成功 续期15秒
                stringRedisTemplate.expire(TY_LOCK_KEY, 15, TimeUnit.MINUTES);
                // log.info("msg---------------------------->:{}", JSON.toJSON(to));
            } catch (Exception e) {
                //途中报错释放锁，lua保证获取后值对比和删除原子性
                String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
                Long release = stringRedisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Lists.newArrayList(TY_LOCK_KEY), LOCK_VALUE);
                long seconds = 0;
                if (!Objects.equals(release, 1L)) {
                    //释放失败 等待释放 记录时间
                    long time = System.currentTimeMillis() - startTime;
                    seconds = TimeUnit.MILLISECONDS.toSeconds(time);
                    log.debug("锁释放失败，距离过期还剩：{}秒", seconds);
                }
                //释放成功 seconds=0
                String serializable = seconds == 0L ? "" : "，稍等：" + seconds + "秒后重试！";
                throw new BeanCreationException(e.getMessage() + serializable);
            }
        } else {
            //未加锁成功，提示稍后重试
            Long expire = stringRedisTemplate.opsForValue().getOperations().getExpire(TY_LOCK_KEY, TimeUnit.MINUTES);
            String time = Objects.nonNull(expire) && expire > 0L ? "，稍等：" + expire + "秒后重试！" : "";
            throw new BeanCreationException(CommonExceptionEnum.TYSJJJYWFM.getMsg() + time);
        }
        return ResponseResult.ok();
    }

    /**
     * @param store
     * @param tpbWechatBankAccount
     * @param certificate
     * @param to
     * @return void
     * @description 结算银行账户
     * 请填写商家提现收款的银行账户信息
     * @author zhangyiheng
     * @date 2024/10/19 16:55
     */
    private void clearingBankAccount(MtStore store, TpbWechatBankAccountEntity tpbWechatBankAccount, X509Certificate certificate, WechatpayTyjjTo to) {
        Bank_account_info bankAccountInfo = new Bank_account_info();

        /*
        账户类型
        1、若主体为企业/政府机关/事业单位/社会组织，可填写：对公银行账户。
        2、若主体为个体户，可选择填写：对公银行账户或经营者个人银行卡。
        BANK_ACCOUNT_TYPE_CORPORATE：对公银行账户
        BANK_ACCOUNT_TYPE_PERSONAL：经营者个人银行卡
         */
        if (!Objects.equals(store.getPrincipalType(), SOHO)) {
            switch (tpbWechatBankAccount.getUsageType()) {
                case TO_THE_PUBLIC:
                    bankAccountInfo.setBank_account_type("BANK_ACCOUNT_TYPE_CORPORATE");
                    break;
                case TO_THE_PRIVATE:
                    bankAccountInfo.setBank_account_type("BANK_ACCOUNT_TYPE_PERSONAL");
                    break;
                default:
                    break;
            }
        } else {
            bankAccountInfo.setBank_account_type("BANK_ACCOUNT_TYPE_PERSONAL");
        }

        /*
        开户名称
        1、选择“经营者个人银行卡”时，开户名称必须与“经营者证件姓名”一致，
        2、选择“对公银行账户”时，开户名称必须与营业执照上的“商户名称”一致
         */
        String bankAccountType = bankAccountInfo.getBank_account_type();
        if (Objects.equals(bankAccountType, "BANK_ACCOUNT_TYPE_CORPORATE")) {
            //对公
            bankAccountInfo.setAccount_name(wechatPayJJCommonService.rsaEncryptOAEP(store.getLicenseName(), certificate));
        } else {
            bankAccountInfo.setAccount_name(wechatPayJJCommonService.rsaEncryptOAEP(store.getContact(), certificate));
        }

        /*
        开户银行
        2、非17家直连银行，该参数请填写为“其他银行”。
        https://pay.weixin.qq.com/wiki/doc/apiv3_partner/terms_definition/chapter1_1_3.shtml#part-4
         */
        bankAccountInfo.setAccount_bank(tpbWechatBankAccount.getAccountBank());

        /*
        开户银行省市编码
        至少精确到市
        仅当省市区编号对照表中无对应的省市区编号时，可向上取该银行对应市级编号或省级编号。
         */
        String areaName = "";
        if (StrUtil.isAllNotBlank(tpbWechatBankAccount.getAccountInstProvince(), tpbWechatBankAccount.getAccountInstCity())) {
            areaName = tpbWechatBankAccount.getAccountInstProvince() + "," + tpbWechatBankAccount.getAccountInstCity();
        } else if (StrUtil.isNotBlank(tpbWechatBankAccount.getAccountInstProvince())) {
            areaName = tpbWechatBankAccount.getAccountInstProvince();
        } else {
            throw new BeanCreationException("开户银行省市信息未填写，不能进件");
        }
        MtProvincesNumTableEntity provincesNumTable = mtProvincesNumTableService.getOne(Wrappers.<MtProvincesNumTableEntity>lambdaQuery().eq(MtProvincesNumTableEntity::getAreaName, areaName));

        Opt.ofNullable(provincesNumTable)
                .orElse(provincesNumTable = mtProvincesNumTableService.getOne(Wrappers.<MtProvincesNumTableEntity>lambdaQuery()
                        .eq(MtProvincesNumTableEntity::getAreaName, tpbWechatBankAccount.getAccountInstProvince())));

        bankAccountInfo.setBank_address_code(provincesNumTable.getProvincialCode());


        /*
        开户银行联行号
        1、17家直连银行无需填写，如为其他银行，则开户银行全称（含支行）和开户银行联行号二选一。
         */
        // bankAccountInfo.setBank_branch_id();

        /*
        开户银行全称（含支行）
        1、17家直连银行无需填写，如为其他银行，则开户银行全称（含支行）和 开户银行联行号二选一。
         */
        if (Objects.equals("其他银行", tpbWechatBankAccount.getAccountBank())) {
            Opt.ofBlankAble(tpbWechatBankAccount.getAccountBranchName()).orElseThrow(BeanCreationException::new, "检查开户银行全称（含支行）是否填写");
            bankAccountInfo.setBank_name(tpbWechatBankAccount.getAccountBranchName());
        }

        /*
        银行账号
        1、数字，长度遵循系统支持的卡号长度要求表。
         */
        bankAccountInfo.setAccount_number(wechatPayJJCommonService.rsaEncryptOAEP(tpbWechatBankAccount.getBankCardNumber(), certificate));

        to.setBank_account_info(bankAccountInfo);
    }


    /**
     * @param store
     * @param cate
     * @param mtUploadCateCertificationLogs
     * @param to
     * @return void
     * @description 结算规则
     * 请填写商家的结算费率规则、特殊资质等信息
     * @author zhangyiheng
     * @date 2024/10/19 15:56
     */
    private void settlementRules(MtStore store, MtStoreCateEntity cate, List<MtUploadCateCertificationLogEntity> mtUploadCateCertificationLogs, WechatpayTyjjTo to) {
        Settlement_info settlementInfo = new Settlement_info();

        /*
        入驻结算规则ID 必选
        https://kf.qq.com/faq/220228IJb2UV220228uEjU3Q.html
         */
        Integer settlementId = null;
        switch (store.getPrincipalType()) {
            case SOLE_PROPRIETORSHIP:
                //个体
                settlementId = cate.getRulesIndividual();
                break;
            case ENTERPRISE:
                //企业
                settlementId = cate.getRulesEnterprise();
                break;
            case SOHO:
                //小微/个人/其他
                settlementId = cate.getRulesTiny();
                break;
            default:
                break;
        }
        Opt.ofNullable(settlementId)
                .ifPresent(id -> settlementInfo.setSettlement_id(id.toString()))
                .orElseThrow(() -> new BeanCreationException("入驻结算规则未选择，请联系管理人员！"));

        /*
        所属行业 必选
        https://kf.qq.com/faq/220228IJb2UV220228uEjU3Q.html
         */
        settlementInfo.setQualification_type(cate.getWechatCateName());

        /*
        特殊资质图片
        2、最多可上传5张照片
        https://kf.qq.com/faq/220228IJb2UV220228uEjU3Q.html
         */
        if (MyCollUtil.isNotEmpty(mtUploadCateCertificationLogs)) {
            List<String> list = mtUploadCateCertificationLogs.stream().map(MtUploadCateCertificationLogEntity::getImageUrl).collect(Collectors.toList());
            while (list.size() > 5) {
                list.remove(list.size() - 1);
            }
            settlementInfo.setQualifications(list);
        }


        /*
        优惠费率活动ID
        选择指定活动ID，如果商户有意向报名优惠费率活动，该字段必填。
        https://pay.weixin.qq.com/docs/partner/development/glossary/parameter.html
         */
        // settlementInfo.setActivities_id("");


        /*
        优惠费率活动值 选填
         */
        // settlementInfo.setActivities_rate("");

        /*
        非信用卡活动费率值 选填
         */
        // settlementInfo.setDebit_activities_rate("");

        /*
        信用卡活动费率值 选填
         */
        // settlementInfo.setCredit_activities_rate("");

        /*
        优惠费率活动补充材料 选填
         */
        // settlementInfo.setActivities_additions("");

        to.setSettlement_info(settlementInfo);
    }


    /**
     * @param store
     * @param to
     * @return void
     * @description 经营资料
     * 请填写商家的经营业务信息、售卖商品/提供服务场景信息
     * @author zhangyiheng
     * @date 2024/10/19 15:25
     */
    private void businessInformation(MtStore store, WechatpayTyjjTo to) {
        Business_info businessInfo = new Business_info();

        /*
        商户简称
        在支付完成页向买家展示，需与微信经营类目相关
         */
        businessInfo.setMerchant_shortname(store.getName());

        /*
        客服电话
        将在交易记录中向买家展示，请确保电话畅通以便平台回拨确认
         */
        businessInfo.setService_phone(store.getPhone());

        /*
        经营场景
        请根据实际经营情况，填写经营场景
         */
        Sales_info salesInfo = new Sales_info();

        /*
        经营场景类型
        1、请勾选实际售卖商品/提供服务场景（至少一项），以便为你开通需要的支付权限。
        2、建议只勾选目前必须的场景，以便尽快通过入驻审核，其他支付权限可在入驻后再根据实际需要发起申请。
        SALES_SCENES_STORE：线下场所
        SALES_SCENES_MP：公众号
        SALES_SCENES_MINI_PROGRAM：小程序
        SALES_SCENES_WEB：互联网网站
        SALES_SCENES_APP：APP
        SALES_SCENES_WEWORK：企业微信
         */
        salesInfo.setSales_scenes_type(SALES_SCENES_TYPE);

        /*
        线下场所场景
        1、审核通过后，服务商可帮商户发起付款码支付、JSAPI支付。
        2、当"经营场景类型"选择"SALES_SCENES_STORE"，该场景资料必填。
         */
        Biz_store_info bizStoreInfo = new Biz_store_info();
        /*
        线下场所名称
         */
        bizStoreInfo.setBiz_store_name(store.getName());

        /*
        线下场所省市编码
        https://pay.weixin.qq.com/docs/partner/development/glossary/parameter.html
         */
        String areaName = "";
        if (StrUtil.isAllNotBlank(store.getProvince(), store.getCity(), store.getCounty())) {
            areaName = store.getProvince() + "," + store.getCity() + "," + store.getCounty();
        } else if (StrUtil.isAllNotBlank(store.getProvince(), store.getCity())) {
            areaName = store.getProvince() + "," + store.getCity();
        } else if (StrUtil.isNotBlank(store.getProvince())) {
            areaName = store.getProvince();
        } else {
            throw new BeanCreationException("店铺省市区信息未填写，不能进件");
        }
        MtProvincesNumTableEntity provincesNumTable = mtProvincesNumTableService.getOne(Wrappers.<MtProvincesNumTableEntity>lambdaQuery().eq(MtProvincesNumTableEntity::getAreaName, areaName));
        bizStoreInfo.setBiz_address_code(provincesNumTable.getProvincialCode());

        /*
        线下场所地址
         */
        bizStoreInfo.setBiz_store_address(store.getAddress());

        /*
        线下场所门头照片
        参考：https://kf.qq.com/faq/230615QVJzqE230615nmQrQb.html
         */
        bizStoreInfo.setStore_entrance_pic(Lists.newArrayList(wechatPayJJCommonService.wxGetImageMediaId(store.getDoorPhotographUrl())));

        /*
        线下场所内部照片
        https://kf.qq.com/faq/230615QVJzqE230615nmQrQb.html
         */
        bizStoreInfo.setIndoor_pic(Lists.newArrayList(wechatPayJJCommonService.wxGetImageMediaId(store.getInteriorUrl())));

        /*
        线下场所对应的商家AppID
        1、可填写与商家主体一致且已认证的公众号、小程序、APP的AppID，其中公众号AppID需是已认证的服务号、政府或媒体类型的订阅号；
        2、审核通过后，系统将额外为商家开通付款码支付、JSAPI支付的自有交易权限，并完成商家商户号与该AppID的绑定；
        （可能需要为商家开发或申请公众号或开发小程序等）
         */
        // bizStoreInfo.setBiz_sub_appid(appid);

        salesInfo.setBiz_store_info(bizStoreInfo);


        /*
        小程序场景
        1、审核通过后，服务商可帮商家发起JSAPI支付
         */
        Mini_program_info miniProgramInfo = new Mini_program_info();

        /*
        服务商小程序APPID
         */
        miniProgramInfo.setMini_program_appid(appid);

        /*
       TODO 小程序截图
        1、请提供展示商品/服务的页面截图/设计稿（最多5张），若小程序未建设完善或未上线 请务必提供；
        2、请填写通过图片上传API预先上传图片生成好的MediaID。
         */
        miniProgramInfo.setMini_program_pics(Lists.newArrayList("https://gulimall-zhangzhan.oss-cn-beijing.aliyuncs.com/applet/491ab26344ffd8a609ef2c54edb19b1.png"));

        salesInfo.setMini_program_info(miniProgramInfo);


        businessInfo.setSales_info(salesInfo);

        to.setBusiness_info(businessInfo);
    }

    /**
     * @param store
     * @param cate
     * @param licenseStartTime
     * @param licenseEndTime
     * @param mtUploadCateCertificationLogs
     * @param cardStartTime
     * @param cardEndTime
     * @param to
     * @return void
     * @description 请填写商家的营业执照/登记证书、经营者/法人的证件等信息
     * @author zhangyiheng
     * @date 2024/10/19 14:32
     */
    private void principalData(MtStore store, MtStoreCateEntity cate, String licenseStartTime, String licenseEndTime, List<MtUploadCateCertificationLogEntity> mtUploadCateCertificationLogs, String cardStartTime, String cardEndTime, WechatpayTyjjTo to, X509Certificate certificate) {
        Subject_info subjectInfo = new Subject_info();

        /*
        主体类型
        https://kf.qq.com/faq/180910IBZVnQ180910naQ77b.html
        SUBJECT_TYPE_INDIVIDUAL（个体户）：营业执照上的主体类型一般为个体户、个体工商户、个体经营；
        SUBJECT_TYPE_ENTERPRISE（企业）：营业执照上的主体类型一般为有限公司、有限责任公司；
        SUBJECT_TYPE_OTHERS（社会组织）/小微： 包括社会团体、民办非企业、基金会、基层群众性自治组织、农村集体经济组织等组织。
         */
        switch (store.getPrincipalType()) {
            case SOLE_PROPRIETORSHIP:
                //个体工商户
                subjectInfo.setSubject_type("SUBJECT_TYPE_INDIVIDUAL");
                break;
            case ENTERPRISE:
                subjectInfo.setSubject_type("SUBJECT_TYPE_ENTERPRISE");
                break;
            case SOHO:
                subjectInfo.setSubject_type("SUBJECT_TYPE_OTHERS");
                break;
            default:
                throw new BeanCreationException(CommonExceptionEnum.UNNOW_EXCEPTION.getMsg());
        }

        /*
        是否是金融机构
        参考：https://kf.qq.com/faq/220215IrMRZ3220215n6buiU.html
         */
        if (Objects.equals(cate.getIsFinancial(), FINANCIAL)) {
            subjectInfo.setFinance_institution(true);
        } else {
            subjectInfo.setFinance_institution(false);
        }

        /*
        营业执照
        1、主体为个体户/企业，必填
        2、请上传“营业执照”，需年检章齐全，当年注册除外
         */
        if (!Objects.equals(store.getPrincipalType(), SOHO) || StrUtil.isNotBlank(store.getLicense())) {
            Business_license_info businessLicenseInfo = new Business_license_info();

            /*
            营业执照照片
             */
            businessLicenseInfo.setLicense_copy(wechatPayJJCommonService.wxGetImageMediaId(store.getLicense()));

            /*
            注册号/统一社会信用代码
             */
            businessLicenseInfo.setLicense_number(store.getCreditCode());

            /*
            商户名称
             */
            businessLicenseInfo.setMerchant_name(trim(store.getLicenseName()));

            /*
            个体户经营者/法人姓名
             */
            businessLicenseInfo.setLegal_person(trim(store.getContact()));

            /*
            注册地址
             */
            businessLicenseInfo.setLicense_address(trim(store.getAddress()));

            /*
            有效期限开始日期
             */
            businessLicenseInfo.setPeriod_begin(licenseStartTime);

            /*
            有效期限结束日期
             */
            businessLicenseInfo.setPeriod_end(licenseEndTime);

            subjectInfo.setBusiness_license_info(businessLicenseInfo);
        }


        /*
        单位证明函照片
        1、主体类型为政府机关、事业单位选传：
         */
        // subjectInfo.setCertificate_letter_copy();


        /*
        金融机构许可证信息
        当主体是金融机构时，必填。
        https://kf.qq.com/faq/220215IrMRZ3220215n6buiU.html
         */
        if (subjectInfo.getFinance_institution()) {
            Finance_institution_info financeInstitutionInfo = new Finance_institution_info();

            /*
            BANK_AGENT：银行业, 适用于商业银行、政策性银行、农村合作银行、村镇银行、开发性金融机构等
            PAYMENT_AGENT：支付机构, 适用于非银行类支付机构
            INSURANCE：保险业, 适用于保险、保险中介、保险代理、保险经纪等保险类业务
            ....
            根据2级行业分类名判断
             */
            switch (cate.getName()) {
                case BANK_AGENT:
                    financeInstitutionInfo.setFinance_type("BANK_AGENT");
                    break;
                case PAYMENT_AGENT:
                    financeInstitutionInfo.setFinance_type("PAYMENT_AGENT");
                    break;
                case INSURANCE:
                    financeInstitutionInfo.setFinance_type("INSURANCE");
                    break;
                case TRADE_AND_SETTLE:
                    financeInstitutionInfo.setFinance_type("TRADE_AND_SETTLE");
                    break;
                case OTHER:
                    financeInstitutionInfo.setFinance_type("OTHER");
                    break;
                default:
                    throw new BeanCreationException("金融机构二级行业分类不正确！");
            }

            /*
            金融机构许可证图片
             在特殊资质图片中查询
             */
            Opt.ofNullable(mtUploadCateCertificationLogs)
                    .ifPresent(item -> {
                        List<String> imageMediaIds = item.stream().map(po -> {
                            String imageUrl = po.getImageUrl();
                            return wechatPayJJCommonService.wxGetImageMediaId(imageUrl);
                        }).collect(Collectors.toList());

                        financeInstitutionInfo.setFinance_license_pics(imageMediaIds);
                    }).orElseThrow(() -> new BeanCreationException("金融行业必须上传金融机构许可证等图片"));


            subjectInfo.setFinance_institution_info(financeInstitutionInfo);
        }


        /*
        -经营者/法人身份证件
        1、个体户：请上传经营者的身份证件。
        2、企业/社会组织：请上传法人的身份证件。
         */
        Identity_info identityInfo = new Identity_info();

        /*
        证件持有人类型
        2. 主体类型为企业、个体户、社会组织时，默认为经营者/法人，不需要上传该字段。
         */
        // identityInfo.setId_holder_type();

        /*
        证件类型
        2、个体户/企业/事业单位/社会组织：可选择任一证件类型，政府机关仅支持中国大陆居民-身份证类型。
        IDENTIFICATION_TYPE_IDCARD：中国大陆居民-身份证
        IDENTIFICATION_TYPE_OVERSEA_PASSPORT：其他国家或地区居民-护照
        IDENTIFICATION_TYPE_HONGKONG_PASSPORT：中国香港居民-来往内地通行证
        IDENTIFICATION_TYPE_MACAO_PASSPORT：中国澳门居民-来往内地通行证
        IDENTIFICATION_TYPE_TAIWAN_PASSPORT：中国台湾居民-来往大陆通行证
        IDENTIFICATION_TYPE_FOREIGN_RESIDENT：外国人居留证
        IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT：港澳居民证
        IDENTIFICATION_TYPE_TAIWAN_RESIDENT：台湾居民证
         */
        identityInfo.setId_doc_type("IDENTIFICATION_TYPE_IDCARD");

        /*
        法定代表人说明函
        1、当证件持有人类型为经办人时，必须上传。其他情况，无需上传。
        https://kf.qq.com/faq/220127aUzAju220127UfiuQr.html
         */
        // identityInfo.setAuthorize_letter_copy();


        /*
        身份证信息
        当证件持有人类型为经营者/法人且证件类型为“身份证”时填写。
         */
        Id_card_info idCardInfo = new Id_card_info();

        /*
        身份证人像面照片
        1、请上传个体户经营者/法人的身份证人像面照片
         */
        idCardInfo.setId_card_copy(wechatPayJJCommonService.wxGetImageMediaId(store.getCardVersaUrl()));

        /*
        身份证国徽面照片
        1、请上传个体户经营者/法定代表人的身份证国徽面照片
         */
        idCardInfo.setId_card_national(wechatPayJJCommonService.wxGetImageMediaId(store.getCardUpUrl()));

        /*
        身份证姓名
        1、请填写个体户经营者/法定代表人对应身份证的姓名
         */
        idCardInfo.setId_card_name(wechatPayJJCommonService.rsaEncryptOAEP(store.getContact(),certificate));

        /*
        身份证号码
         */
        idCardInfo.setId_card_number(wechatPayJJCommonService.rsaEncryptOAEP(store.getIdCard(),certificate));

        /*
        身份证居住地址
         */
        idCardInfo.setId_card_address(wechatPayJJCommonService.rsaEncryptOAEP(store.getIdCardAddress(),certificate));

        /*
        身份证有效期开始时间
         */
        idCardInfo.setCard_period_begin(cardStartTime);

        /*
        身份证有效期结束时间
         */
        idCardInfo.setCard_period_end(cardEndTime);

        identityInfo.setId_card_info(idCardInfo);

        //其他类型证件信息	id_doc_info	object	当证件持有人类型为经营者/法人且证件类型不为“身份证”时填写。

        /*
        经营者/法人是否为受益人
        主体类型为企业时，需要填写：
        1、若经营者/法人是最终受益人，则填写：true。
        2、若经营者/法人不是最终受益人，则
         */
        if (Objects.equals(store.getPrincipalType(), ENTERPRISE)) {
            identityInfo.setOwner(true);
        }

        subjectInfo.setIdentity_info(identityInfo);

        /*
        -最终受益人信息列表(UBO)
        仅企业需要填写。
        若经营者/法人不是最终受益所有人，则需补充受益所有人信息，最多上传4个。
        若经营者/法人是最终受益所有人之一，可在此添加其他受益所有人信息，最多上传3个。
        根据国家相关法律法规，需要提供公司受益所有人信息，受益所有人需符合至少以下条件之一：
        1、直接或者间接拥有超过25%公司股权或者表决权的自然人。
        2、通过人事、财务等其他方式对公司进行控制的自然人。
        3、公司的高级管理人员，包括公司的经理、副经理、财务负责人、上市公司董事会秘书和公司章程规定的其他人员。
         */
        // subjectInfo.setUbo_info_list();

        to.setSubject_info(subjectInfo);
    }


    /**
     * @param certificate
     * @param to
     * @return void
     * @description 超级管理员需在开户后进行签约，并可接收日常重要管理信息和进行资金操作，请确定其为商户法定代表人或负责人。
     * @author zhangyiheng
     * @date 2024/10/19 10:53
     */
    private void superAdministratorInformation(X509Certificate certificate, WechatpayTyjjTo to, WxTySuperAdminVo admin) {
        Contact_info contactInfo = new Contact_info();
        /*
        超级管理员类型
         * 1、主体为“个体工商户/企业/政府机关/事业单位/社会组织”，可选择：LEGAL：经营者/法人，SUPER：经办人 。（经办人：经商户授权办理微信支付业务的人员）。
         * 枚举值：
         * LEGAL：经营者/法人
         * SUPER：经办人
         */
        switch (admin.getContactType()) {
            case LEGAL:
                contactInfo.setContact_type("LEGAL");
                break;
            case SUPER:
                contactInfo.setContact_type("SUPER");
                /*
                 超级管理员证件类型
                 当超级管理员类型是经办人时，请上传超级管理员证件类型。
                 IDENTIFICATION_TYPE_IDCARD：中国大陆居民-身份证
                 IDENTIFICATION_TYPE_OVERSEA_PASSPORT：其他国家或地区居民-护照
                 IDENTIFICATION_TYPE_HONGKONG_PASSPORT：中国香港居民-来往内地通行证
                 IDENTIFICATION_TYPE_MACAO_PASSPORT：中国澳门居民-来往内地通行证
                 IDENTIFICATION_TYPE_TAIWAN_PASSPORT：中国台湾居民-来往大陆通行证
                 IDENTIFICATION_TYPE_FOREIGN_RESIDENT：外国人居留证
                 IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT：港澳居民证
                 IDENTIFICATION_TYPE_TAIWAN_RESIDENT：台湾居民证
                  */
                switch (admin.getContactIdDocType()) {
                    case IDENTIFICATION_TYPE_IDCARD:
                        contactInfo.setContact_id_doc_type("IDENTIFICATION_TYPE_IDCARD");
                        break;
                    case IDENTIFICATION_TYPE_OVERSEA_PASSPORT:
                        contactInfo.setContact_id_doc_type("IDENTIFICATION_TYPE_OVERSEA_PASSPORT");
                        break;
                    case IDENTIFICATION_TYPE_HONGKONG_PASSPORT:
                        contactInfo.setContact_id_doc_type("IDENTIFICATION_TYPE_HONGKONG_PASSPORT");
                        break;
                    case IDENTIFICATION_TYPE_MACAO_PASSPORT:
                        contactInfo.setContact_id_doc_type("IDENTIFICATION_TYPE_MACAO_PASSPORT");
                        break;
                    case IDENTIFICATION_TYPE_TAIWAN_PASSPORT:
                        contactInfo.setContact_id_doc_type("IDENTIFICATION_TYPE_TAIWAN_PASSPORT");
                        break;
                    case IDENTIFICATION_TYPE_FOREIGN_RESIDENT:
                        contactInfo.setContact_id_doc_type("IDENTIFICATION_TYPE_FOREIGN_RESIDENT");
                        break;
                    case IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT:
                        contactInfo.setContact_id_doc_type("IDENTIFICATION_TYPE_HONGKONG_MACAO_RESIDENT");
                        break;
                    case IDENTIFICATION_TYPE_TAIWAN_RESIDENT:
                        contactInfo.setContact_id_doc_type("IDENTIFICATION_TYPE_TAIWAN_RESIDENT");
                        break;
                    default:
                        break;
                }

                /*
                超级管理员身份证件号码
                1、当超级管理员类型是经办人时，请上传超级管理员证件号码
                 */
                contactInfo.setContact_id_number(wechatPayJJCommonService.rsaEncryptOAEP(admin.getContactIdNumber(), certificate));

                /*
                超级管理员证件正面照片
                1、当超级管理员类型是经办人时，请上传超级管理员证件的正面照片。
                 */
                contactInfo.setContact_id_doc_copy(wechatPayJJCommonService.wxGetImageMediaId(admin.getContactIdDocCopy()));

                /*
                超级管理员证件反面照片
                1、当超级管理员类型是经办人时，请上传超级管理员证件的反面照片。
                 */
                contactInfo.setContact_id_doc_copy_back(wechatPayJJCommonService.wxGetImageMediaId(admin.getContactIdDocCopyBack()));

                String contactPeriodBegin = DateUtil.format(admin.getContactPeriodBegin(), "yyyy-MM-dd");
                String contactPeriodEnd = DateUtil.format(admin.getContactPeriodEnd(), "yyyy-MM-dd");

                /*
                超级管理员证件有效期开始时间
                1、当超级管理员类型是经办人时，请上传证件有效期开始时间。
                 */
                contactInfo.setContact_period_begin(contactPeriodBegin);

                /*
                超级管理员证件有效期结束时间
                1、当超级管理员类型是经办人时，请上传证件有效期结束时间。
                 */
                contactInfo.setContact_period_end(contactPeriodEnd);

                /*
                业务办理授权函
                1、当超级管理员类型是经办人时，请上传业务办理授权函。
                //请参照 https://kf.qq.com/faq/220509Y3Yvym220509fQvYR7.html
                 */
                contactInfo.setBusiness_authorization_letter(wechatPayJJCommonService.wxGetImageMediaId(admin.getBusinessAuthorizationLetter()));
                break;
            default:
                break;
        }

        /*
        超级管理员姓名
        1、长度为2-100个字符
        2、前后不能有空格、制表符、换行符
        3、不能仅含数字、特殊字符
        4、仅能填写数字、英文字母、汉字及特殊字符
        该字段需进行加密处理，加密方法详见敏感信息加密说明。
         */
        contactInfo.setContact_name(wechatPayJJCommonService.rsaEncryptOAEP(admin.getContactName(), certificate));

        /*
        超级管理员微信OpenID
        该字段选填，若上传为超级管理员签约时，会校验微信号是否与该微信OpenID一致
         */
        //contactInfo.setOpenid("");

        /*
        联系手机
         */
        contactInfo.setMobile_phone(wechatPayJJCommonService.rsaEncryptOAEP(admin.getMobilePhone(), certificate));

        /*
        联系邮箱
        1、用于接收微信支付的开户邮件及日常业务通知；
         */
        contactInfo.setContact_email(wechatPayJJCommonService.rsaEncryptOAEP(admin.getContactEmail(), certificate));

        to.setContact_info(contactInfo);
    }

    private String trim(String content) {
        return StrUtil.trim(content);
    }
}
